package cn.edu.dutir.utility;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.aliasi.util.Streams;

/**
 * Useful utilities for manipulating List, Map ,Set and Collections.
 * 
 * @author Su Sui
 * 
 */
public class WordListMgr {

	/**
	 * Write word list to output file
	 * 
	 * @param wordList the list to write
	 * @param outFile the file to be written to
	 * @param charset encoding charset of the output file
	 * @throws IOException
	 */

	public static void writeWordList(List wordList, File outFile)
			throws IOException {
		writeWordList(wordList, outFile, Constants.DEFAULT_CHARSET);
	}

	public static void writeWordList(List wordList, File outFile,
			int buffer_size) throws IOException {
		writeWordList(wordList, outFile, Constants.DEFAULT_CHARSET, buffer_size);
	}

	public static void writeWordList(List wordList, File outFile, String charset)
			throws IOException {
		writeWordList(wordList, outFile, charset, Constants.DEFAULT_BUFFER_SIZE);
	}

	public static void writeWordList(List wordList, File outFile,
			String charset, int buffer_size) throws IOException {
		BufferedWriter bufWriter = null;
		OutputStreamWriter outputStream = null;
		FileOutputStream fileStream = null;
		try {
			fileStream = new FileOutputStream(outFile);
			outputStream = new OutputStreamWriter(fileStream, charset);
			bufWriter = new BufferedWriter(outputStream, buffer_size);
			writeWordList(wordList, bufWriter);
		} finally {
			Streams.closeOutputStream(fileStream);
			Streams.closeWriter(outputStream);
			Streams.closeWriter(bufWriter);
		}
	}

	public static void writeWordList(List wordList, Writer writer)
			throws IOException {
		BufferedWriter bufWriter = null;
		if (writer instanceof BufferedWriter) {
			bufWriter = (BufferedWriter) bufWriter;
		} else {
			bufWriter = new BufferedWriter(writer);
		}
		for (Object elem : wordList) {
			bufWriter.write(elem.toString());
			bufWriter.newLine();
		}
	}

	/**
	 * Load Set from specified file
	 * 
	 * @param filename the input file
	 * @return
	 * @throws IOException
	 */
	public static Set<String> loadSet(String filename) throws IOException {
		return loadSet(new File(filename));
	}

	public static Set<String> loadSet(File inFile) throws IOException {
		return loadSet(inFile, Constants.DEFAULT_CHARSET);
	}

	public static Set<String> loadSet(File inFile, int buffer_size)
			throws IOException {
		return loadSet(inFile, Constants.DEFAULT_CHARSET, buffer_size);
	}

	public static Set<String> loadSet(File inFile, String charset)
			throws IOException {
		return loadSet(inFile, charset, Constants.DEFAULT_BUFFER_SIZE);
	}

	public static Set<String> loadSet(File inFile, String charset,
			int buffer_size) throws IOException {
		Set<String> set = null;
		BufferedReader bufReader = null;
		InputStreamReader inputReader = null;
		FileInputStream fileStream = null;
		try {
			fileStream = new FileInputStream(inFile);
			inputReader = new InputStreamReader(fileStream, charset);
			bufReader = new BufferedReader(inputReader, buffer_size);
			set = loadSet(bufReader);
		} finally {
			Streams.closeInputStream(fileStream);
			Streams.closeReader(inputReader);
			Streams.closeReader(bufReader);
		}
		return set;
	}

	public static Set<String> loadSet(Reader reader) throws IOException {
		HashSet<String> set = new HashSet<String>();
		BufferedReader bufReader = null;
		if (reader instanceof BufferedReader) {
			bufReader = (BufferedReader) reader;
		} else {
			bufReader = new BufferedReader(reader);
		}
		String word = null;
		while ((word = bufReader.readLine()) != null) {
			set.add(word.trim());
		}
		return set;
	}

	public static Set<String> loadSet(String wordlist[]) {
		Set<String> set = new HashSet<String>(wordlist.length);
		for (String word : wordlist) {
			set.add(word);
		}
		return set;
	}

	public static Set<String> loadSet(List<String> wordList) {
		String words[] = wordList.toArray(new String[wordList.size()]);
		return loadSet(words);
	}

	/**
	 * Load HashMap from specified input file
	 * 
	 * @param filename
	 *            the input file
	 * @return loaded Loaded HashMap
	 * @throws IOException
	 */
	
	public static Map<String, String> loadMap(String filename,
			String delimiter, boolean opposite) throws IOException {
		return loadMap(new File(filename), delimiter, opposite);
	}
	
	public static Map<String, String> loadMap(File inFile, String delimiter)
			throws IOException {
		return loadMap(inFile, delimiter, false);
	}

	public static Map<String, String> loadMap(File inFile, String delimiter,
			boolean opposite) throws IOException {
		return loadMap(inFile, Constants.DEFAULT_CHARSET, delimiter, opposite);
	}

	public static Map<String, String> loadMap(File inFile, String delimiter,
			int buffer_size, boolean opposite) throws IOException {
		return loadMap(inFile, Constants.DEFAULT_CHARSET, delimiter,
				buffer_size, opposite);
	}

	public static Map<String, String> loadMap(File inFile, String charset,
			String delimiter, boolean opposite) throws IOException {
		return loadMap(inFile, charset, delimiter,
				Constants.DEFAULT_BUFFER_SIZE, opposite);
	}

	public static Map<String, String> loadMap(File inFile, String charset,
			String delimiter, int buffer_size, boolean opposite)
			throws IOException {
		Map<String, String> map = null;
		BufferedReader bufReader = null;
		InputStreamReader inputReader = null;
		FileInputStream fileStream = null;
		try {
			fileStream = new FileInputStream(inFile);
			inputReader = new InputStreamReader(fileStream, charset);
			bufReader = new BufferedReader(inputReader, buffer_size);
			map = loadMap(bufReader, delimiter, opposite);
		} finally {
			Streams.closeInputStream(fileStream);
			Streams.closeReader(inputReader);
			Streams.closeReader(bufReader);
		}
		return map;
	}

	public static Map<String, String> loadMap(Reader reader, String delimiter,
			boolean opposite) throws IOException {
		BufferedReader bufReader = null;
		Map<String, String> map = new HashMap<String, String>();

		if (reader instanceof BufferedReader) {
			bufReader = (BufferedReader) reader;
		} else {
			bufReader = new BufferedReader(reader);
		}
		String text = null;
		int lineNumber = 0;
		while ((text = bufReader.readLine()) != null) {
			lineNumber++;
			String fields[] = text.split(delimiter);
			if (fields == null || fields.length != 2) {
				System.out.println("Invalid input found at line " + lineNumber
						+ " with text = '" + text + "'");
				continue;
			}
			if (!opposite) {
				map.put(fields[1], fields[0]);
			} else {
				map.put(fields[0], fields[1]);
			}
		}
		return map;
	}

	/**
	 * Write HashSet to specified output file
	 * 
	 * @param wordSet the HashSet to write
	 * @param outFile the specified output file
	 * @param delimiter line separator using LINE_SEP as default value
	 * @throws IOException  
	 */	
	public static void writeSet(Set<String> set, String filename)
			throws IOException {
		writeSet(set, new File(filename));
	}

	public static void writeSet(Set<String> set, File outFile)
			throws IOException {
		writeSet(set, outFile, Constants.NEWLINE);
	}

	public static void writeSet(Set<String> set, String filename,
			String delimiter) throws IOException {
		writeSet(set, new File(filename), delimiter);
	}

	public static void writeSet(Set<String> set, File outFile, String delimiter)
			throws IOException {
		writeSet(set, outFile, delimiter, Constants.DEFAULT_CHARSET);
	}

	public static void writeSet(Set<String> set, File outFile,
			String delimiter, int buffer_size) throws IOException {
		writeSet(set, outFile, delimiter, Constants.DEFAULT_CHARSET,
				buffer_size);
	}

	public static void writeSet(Set<String> set, File outFile,
			String delimiter, String charset) throws IOException {
		writeSet(set, outFile, delimiter, charset,
				Constants.DEFAULT_BUFFER_SIZE);
	}
	
	public static void writeSet(Set<String> set, File outFile,
			String delimiter, String charset, int buffer_size)
			throws IOException {
		BufferedWriter bufWriter = null;
		OutputStreamWriter outputStream = null;
		FileOutputStream fileStream = null;
		try {
			fileStream = new FileOutputStream(outFile);
			outputStream = new OutputStreamWriter(fileStream, charset);
			bufWriter = new BufferedWriter(outputStream, buffer_size);
			writeSet(set, bufWriter, delimiter);
		} finally {
			Streams.closeOutputStream(fileStream);
			Streams.closeWriter(outputStream);
			Streams.closeWriter(bufWriter);
		}
	}
	
	public static void writeSet(Set<String> set, Writer writer)
			throws IOException {
		writeSet(set, writer, Constants.NEWLINE);
	}

	public static void writeSet(Set<String> set, Writer writer,
			String delimiter) throws IOException {
		BufferedWriter bufWriter = null;
		if (writer instanceof BufferedWriter) {
			bufWriter = (BufferedWriter) writer;
		} else {
			bufWriter = new BufferedWriter(writer);
		}
		Iterator<String> iter = set.iterator();
		while (iter.hasNext()) {
			bufWriter.write(iter.next() + delimiter);
		}
	}

	/**
	 * 
	 * @param wordMap
	 *            the HashMap to output
	 * @param outFile
	 *            the file where the HashMap write to
	 * @param gapSep
	 *            separator between Map.Key and Map.Value using GAP_SEP as
	 *            default value
	 * @param lineSep
	 *            line separator using LINE_SEP as default value
	 * @throws IOException
	 */
	public static void writeMap(Map map, String filename)
			throws IOException {
		writeMap(map, new File(filename));
	}

	public static void writeMap(Map map, File outFile) throws IOException {
		writeMap(map, outFile, Constants.DEFAULT_DEMILTER);
	}

	public static void writeMap(Map map, File outFile, String delimiter)
			throws IOException {
		writeMap(map, outFile, delimiter, false);
	}

	public static void writeMap(Map map, String filename, String delimiter)
			throws IOException {
		writeMap(map, new File(filename), delimiter);
	}

	public static void writeMap(Map map, File outFile, String delimiter,
			boolean opposite) throws IOException {
		writeMap(map, outFile, delimiter, Constants.DEFAULT_BUFFER_SIZE,
				opposite);
	}

	public static void writeMap(Map map, File outFile, String delimiter,
			int buffer_size, boolean opposite) throws IOException {
		writeMap(map, outFile, delimiter, Constants.DEFAULT_CHARSET,
				buffer_size, opposite);
	}

	public static void writeMap(Map map, File outFile, String delimiter,
			String charset, boolean opposite) throws IOException {
		writeMap(map, outFile, delimiter, charset,
				Constants.DEFAULT_BUFFER_SIZE, opposite);
	}

	public static void writeMap(Map map, File outFile, String delimiter,
			String charset, int buffer_size) throws IOException {
		writeMap(map, outFile, delimiter, charset, buffer_size, false);
	}
	
	public static void writeMap(Map map, File outFile, String delimiter,
			String charset, int buffer_size, boolean opposite)
			throws IOException {
		BufferedWriter bufWriter = null;
		OutputStreamWriter outputStream = null;
		FileOutputStream fileStream = null;
		try {
			fileStream = new FileOutputStream(outFile);
			outputStream = new OutputStreamWriter(fileStream, charset);
			bufWriter = new BufferedWriter(outputStream, buffer_size);
			writeMap(map, bufWriter, delimiter, opposite);
		} finally {
			Streams.closeOutputStream(fileStream);
			Streams.closeWriter(outputStream);
			Streams.closeWriter(bufWriter);
		}
	}
	
	public static void writeMap(Map map, Writer writer, String delimiter)
			throws IOException {
		writeMap(map, writer, delimiter, false);
	}

	public static void writeMap(Map map, Writer writer, boolean opposite)
			throws IOException {
		writeMap(map, writer, Constants.DEFAULT_DEMILTER, opposite);
	}
	
	public static void writeMap(Map map, Writer writer, String delimiter,
			boolean opposite) throws IOException {
		BufferedWriter bufWriter = null;
		if (writer instanceof BufferedWriter) {
			bufWriter = (BufferedWriter) writer;
		} else {
			bufWriter = new BufferedWriter(writer);
		}
		Iterator iter = map.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			if (!opposite) {
				bufWriter.write(entry.getKey() + delimiter + entry.getValue());
			} else {
				bufWriter.write(entry.getValue() + delimiter + entry.getKey());
			}
			bufWriter.newLine();
		}
	}

	/**
	 * Write word collection to output file
	 * 
	 * @param c the Collection to write
	 * @param outFile the specified output file
	 * @param delimiter line separator using LINE_SEP as default value
	 * @throws IOException
	 */
	public static void writeCollection(Collection c, String outFile,
			String delimiter) throws IOException {
		writeCollection(c, new File(outFile), delimiter);
	}

	public static void writeCollection(Collection c, File outFile,
			String delimiter) throws IOException {
		writeCollection(c, outFile, delimiter, Constants.DEFAULT_BUFFER_SIZE);
	}

	public static void writeCollection(Collection c, File outFile,
			String delimiter, int buffer_size) throws IOException {
		writeCollection(c, outFile, delimiter, Constants.DEFAULT_CHARSET,
				buffer_size);
	}

	public static void writeCollection(Collection c, File outFile,
			String delimiter, String charset) throws IOException {
		writeCollection(c, outFile, delimiter, charset,
				Constants.DEFAULT_BUFFER_SIZE);
	}

	public static void writeCollection(Collection c, File outFile,
			String delimiter, String charset, int buffer_size)
			throws IOException {
		BufferedWriter bufWriter = null;
		OutputStreamWriter outputStream = null;
		FileOutputStream fileStream = null;
		try {
			fileStream = new FileOutputStream(outFile);
			outputStream = new OutputStreamWriter(fileStream, charset);
			bufWriter = new BufferedWriter(outputStream, buffer_size);
			writeCollection(c, bufWriter, delimiter);
		} finally {
			Streams.closeOutputStream(fileStream);
			Streams.closeWriter(outputStream);
			Streams.closeWriter(bufWriter);
		}
	}

	public static void writeCollection(Collection c, Writer writer,
			String delimiter) throws IOException {
		BufferedWriter bufWriter = null;
		if (writer instanceof BufferedWriter) {
			bufWriter = (BufferedWriter) writer;
		} else {
			bufWriter = new BufferedWriter(writer);
		}
		Iterator iter = c.iterator();
		while (iter.hasNext()) {
			bufWriter.write(iter.next() + delimiter);
		}
	}
}

